﻿using MahApps.Metro.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace LunarSF.SHomeWorkshop.LunarMarkdownEditor
{
    /// <summary>
    /// InputBox.xaml 的交互逻辑
    /// </summary>
    public partial class InputBox : MetroWindow
    {
        /// <summary>
        /// [私有构造方法]用以创建一个输入窗口。
        /// 此类只用静态方法调用，所以不需要公有的构造方法。
        /// 调用方式：InputBox.Show(...);
        /// </summary>
        private InputBox()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 显示一个输入框，并获取输入的数据。
        /// </summary>
        /// <param name="title">输入框标题。</param>
        /// <param name="prompt">输入框中的提示文本。</param>
        /// <param name="defaultValue">输入框的默认文本。</param>
        /// <param name="isFilePath">是否应输入文件名。这会影响数据校验的结果。</param>
        /// <param name="prompt2">第二提示文本。</param>
        /// <param name="isPassword">是否打算输入密码。如果为真，输入时文本透明（不可见）。</param>
        /// <param name="closeIME">是否关闭输入法</param>
        /// <param name="imageSource">图像</param>
        /// <param name="imgWidth">图像推荐尺寸，不会大于120。</param>
        /// <param name="imgHeight">图像推荐尺寸，不会大于120。</param>
        /// <param name="multiLines">是否支持多行。</param>
        /// <param name="replaceSpaces">是否将空格替换为 -。</param>
        public static string Show(string title, string prompt, string defaultValue, bool isFilePath,
            string prompt2 = null, bool isPassword = false, bool? closeIME = null,
            ImageSource imageSource = null, int? imgWidth = 120, int? imgHeight = 120, bool multiLines = false, bool replaceSpaces = false)
        {
            try
            {
                InputBox ibx = new InputBox();
                ibx.Owner = App.Current.MainWindow;
                ibx.WindowStartupLocation = WindowStartupLocation.CenterOwner;
                ibx.Icon = ibx.Owner.Icon;
                ibx.Title = string.IsNullOrWhiteSpace(title) ? (Globals.AppName + " - 输入框") : title;
                ibx.tbxPrompt.Text = prompt;
                ibx.tbxInput.Text = defaultValue;
                ibx.IsPassword = isPassword;
                ibx.isFilePath = isFilePath;
                if (imageSource != null)
                {
                    ibx.imgBorder.Width = Math.Min(120, imgWidth.Value);
                    ibx.imgBorder.Height = Math.Min(120, imgWidth.Value);
                    ibx.imgBorder.Margin = new Thickness(5);
                    ibx.imageBox.Source = imageSource;
                }

                if (string.IsNullOrEmpty(prompt2))
                {
                    ibx.tbxPrompt2.Visibility = Visibility.Collapsed;
                }
                else
                {
                    ibx.tbxPrompt2.Visibility = Visibility.Visible;
                    ibx.tbxPrompt2.Text = prompt2;
                }

                ibx.tbxInput.SelectAll();

                if (closeIME != null && closeIME.HasValue)
                {
                    if (closeIME.Value)
                    {
                        var typeOfLanguage = new System.Globalization.CultureInfo("zh-cn");
                        System.Windows.Forms.InputLanguage.CurrentInputLanguage = System.Windows.Forms.InputLanguage.FromCulture(typeOfLanguage);

                        InputMethod.SetIsInputMethodEnabled(ibx, true);
                        InputMethod.Current.ImeState = InputMethodState.On;
                    }
                    else
                    {
                        var typeOfLanguage = new System.Globalization.CultureInfo("en-us");
                        System.Windows.Forms.InputLanguage.CurrentInputLanguage = System.Windows.Forms.InputLanguage.FromCulture(typeOfLanguage);
                    }
                }

                if (isPassword)
                {
                    //ibx.tbxInput.SelectionBrush =
                    //ibx.tbxInput.CaretBrush =
                    ibx.tbxInput.Foreground = Brushes.Transparent;
                }

                if (multiLines)
                {
                    ibx.tbxInput.AcceptsReturn = true;
                    ibx.tbxInput.VerticalScrollBarVisibility = ScrollBarVisibility.Visible;
                    ibx.tbxInput.Height = 400;
                    ibx.tbxInput.VerticalContentAlignment = VerticalAlignment.Top;
                }
                else
                {
                    ibx.tbxInput.Height = 24;
                    ibx.tbxInput.VerticalContentAlignment = VerticalAlignment.Center;
                }

                if (ibx.ShowDialog() == true)
                {
                    if (isFilePath && isPassword == false)
                    {
                        string result;
                        if (replaceSpaces)
                        {
                            result = ibx.tbxInput.Text.Replace(" ", "-");
                        }
                        else
                        {
                            result = ibx.tbxInput.Text;
                        }

                        if (result.StartsWith("_"))
                            result = result.Substring(1);

                        result = result.Replace("_", "-");
                        if (result.ToLower() == "readme" || result.ToLower() == "readme.md")
                        {
                            result = "README.md";
                        }
                        return result;
                    }
                    else
                    {
                        return ibx.tbxInput.Text;//原文输出
                    }
                }

                return null;
            }
            catch (Exception ex)
            {
                LMessageBox.Show(ex.Message, Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
                return "";
            }
        }

        /// <summary>
        ///  密码应原文输出。
        /// </summary>
        public bool IsPassword { get; set; } = false;

        /// <summary>
        /// 完成输入。
        /// </summary>
        private void btnOK_Click(object sender, RoutedEventArgs e)
        {
            if (IsFilePath)
            {
                if (ValidateFilePath(this.tbxInput.Text, true) == false)
                {
                    if (ValidateFilePath(this.tbxInput.Text, false))
                    {
                        var result = LMessageBox.Show("建议使用英文字母、数字来命名，并且最好以英文字母开头（某些网络设备对数字开头的文件名支持欠佳）。\r\n" +
                            "　　文件名（或文件夹名）使用特殊字符或汉字可能导致编译出的 CHM 文档中某些链接无效。" +
                            "只有一定范围的汉字会被转换为拼音首字母，而其它字符不会转换，所以仍然可能出错。\r\n\r\n" +
                            "　　你确定要这样做吗？",
                            Globals.AppName, MessageBoxButton.YesNo, MessageBoxImage.Warning, "NPA_UseSpecialCharForFileName");
                        // NPA_ means No Prompt Again.

                        if (result != MessageBoxResult.Yes) return;
                        else
                        {
                            this.DialogResult = true;
                            this.Close();
                            return;
                        }
                    }
                    else
                    {
                        //var forbidonChars1 = "\\ / : * \" < > |";
                        //var forbidonChars2 = @"+ "" # % & ( ) + , : ; < = > ? @ |";
                        //tbxPrompt2.Text = $"　　文件名只能使用字母、数字、下划线(_)字符。\r\n　　下列字符为 Windows 文件系统禁用字符：\r\n　　{forbidonChars1}\r\n　　下列特殊字符会造成编译后的 CHM 文件中出现路径错误：\r\n　　{forbidonChars2}";// "文件名中不能包含：\\/:*\"<>|";
                        tbxPrompt2.Text = "　　文件名只能使用字母、数字、下划线(_)字符，且应以字母开头（不能以下划线字符[_]和数字字符和句点开头）。\r\n" +
                            "　　※因为某些网络设备（或软件）对一些特殊字符支持很差。";
                        tbxPrompt2.Visibility = Visibility.Visible;
                        return;
                    }
                }
            }

            this.DialogResult = true;
            this.Close();
        }

        private bool isFilePath = true;
        /// <summary>
        /// 指明输入的文本是否应通过文件名规则校验。
        /// </summary>
        public bool IsFilePath
        {
            get { return isFilePath; }
            set { isFilePath = value; }
        }

        /// <summary>
        /// 与“MainWindow.cs”下的同名方法不同：禁止出现路径分割符。
        /// 只允许字母、数字、下划线、句点，且不能以下划线开头。
        /// </summary>
        /// <param name="text">文件短名。</param>
        /// <returns></returns>
        public static bool ValidateFilePath(string text, bool highLevel)
        {
            if (string.IsNullOrEmpty(text)) return false;
            if (text.StartsWith("_")) return false;
            var shortName = text.Trim(new char[] { ' ', '　', '\t' });

            // if (shortName.ToLower() == "readme" || shortName.ToLower() == "readme.md") return false;
            // 放弃将根目录元文件改造为 readme 的想法——这个太疯狂了，后果根本无法预料。
            // 所以这里应允许用户自行创建 Readme.md 文件。

            if (shortName.StartsWith(".")) return false;

            if (highLevel)
            {
                foreach (char c in text)
                {
                    if (c >= 'a' && c <= 'z') continue;
                    if (c >= 'A' && c <= 'Z') continue;
                    if (c >= '0' && c <= '9') continue;
                    if (c == '_' || c == '.' || c == ' ' || c == '-') continue;

                    return false;
                }

                return true;
            }

            if (text.Contains("/") ||
               text.Contains("\\") ||
               text.Contains(":") ||
               //text.Contains("：") || //已知全角冒号也会导致链接失效，但可通过替换解决问题。
               text.Contains("*") ||
               text.Contains("\"") ||
               text.Contains("<") ||
               text.Contains(">") ||
               text.Contains("|") ||
               text.Contains("[") || //方括号会导致图像链接文本切分时识别出错。
               text.Contains("]"))   //方括号会导致图像链接文本切分时识别出错。
            {
                return false;
            }

            foreach (char c in text)
            {
                //全角标点均可用，半角标点不允许前列特殊字符。另，
                //半角波形符用于资源文件夹，不可用。
                //下划线用于目录元文件，不可用。
                //反引号符备用，不可用。
                //右面这些字符是 URL 要转义的，所以不能使用：+"#%&()+,/:;<=>?@\|
                if (@"+""#%&()+,/:;<=>?@\|".Contains(c)) return false;
                if ("!@$^-{}',.～·＠＃￥％…＆＊（）【】｛｝｜；：‘’“”，。《〈〉》？".Contains(c)) continue;
                //已知全角冒号也会导致 Markdown 文件转换成 Html 文件后图像链接失效。
                //但是可以通过事先替换来解决问题。2024年5月24日
                //全角字符就算是特殊符号也是可以的
                //全角小写字母
                if (c == '、') continue;
                if (c >= 'ａ' && c <= 'ｚ') continue;
                //全角大写字母
                if (c >= 'Ａ' && c <= 'Ｚ') continue;
                //！＂＃＄％＆＇（）＊＋，－．／
                if (c >= '！' && c <= '／') continue;
                //全角数字
                if (c >= '０' && c <= '９') continue;
                //：；＜＝＞？＠
                if (c >= '：' && c <= '＠') continue;
                //［＼］＾＿｀
                if (c >= '［' && c <= '｀') continue;
                //｛｜｝～
                if (c >= '｛' && c <= '～') continue;
                //￠￡￢￣￤￥
                if (c >= '￠' && c <= '￥') continue;
                //全角字符就算是特殊符号也是可以的

                //全角问号'？'，就是>0x9fbb的。
                if (c > 0x9fbb)
                {
                    if (c == '§') continue;
                    if (c == '☆') continue;
                    if (c == '★') continue;
                    if (c == '○') continue;
                    if (c == '●') continue;
                    if (c == '◎') continue;
                    if (c == '◇') continue;
                    if (c == '◆') continue;
                    if (c == '□') continue;
                    if (c == '■') continue;
                    if (c == '△') continue;
                    if (c == '▲') continue;
                    if (c == '※') continue;
                    if (c == '〓') continue;
                    if (c == '＃') continue;
                    if (c == '＆') continue;
                    if (c == '＠') continue;
                    if (c == '＿') continue;
                    if (c == '￣') continue;

                    return false;
                }

                if (c < 0x4e00)
                {
                    if (c >= '0' && c <= '9') continue;
                    if (c == '_') continue;
                    if (c == '+') continue;
                    if (c == '-') continue;
                    if (c == '.') continue;//后缀名需要
                    if (c == '=') continue;
                    if (c == ' ') continue;
                    if (c == '(') continue;
                    if (c == ')') continue;
                    if (c == '）') continue;
                    if (c == '（') continue;
                    if (c >= '⑴' && c <= '⒇') continue;
                    if (c >= '①' && c <= '⑩') continue;
                    if (c >= '⒈' && c <= '⒛') continue;
                    if (c >= 'A' && c <= 'Z') continue;
                    if (c >= 'a' && c <= 'z') continue;

                    return false;
                }
            }

            return true;
        }

        /// <summary>
        /// 放弃输入，关闭窗口。
        /// </summary>
        private void btnCancel_Click(object sender, RoutedEventArgs e)
        {
            //if (IsFilePath)
            //{
            //    if (ValidateFilePath() == false)
            //    {
            //        tbxPrompt2.Text = "文件名中不能包含：\\/:*\"<>|";
            //        return;
            //    }
            //}

            this.DialogResult = false;
            this.Close();
        }

        /// <summary>
        /// 回车键完成输入；Esc键放弃输入。
        /// </summary>
        private void tbxInput_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                btnOK_Click(sender, e);
            }
            else if (e.Key == Key.Escape)
            {
                btnCancel_Click(sender, e);
            }
        }

        /// <summary>
        /// 窗口载入时自动对焦，便于立即开始输入。
        /// </summary>
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            tbxInput?.Focus();
        }
    }
}
